/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = jolt_comm.c                                        */
/*  NOTE      =                                                    */
/*  DATE      = 2015/06/02 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <memory.h>
#include <sys/time.h>

#include "frmem.h"
#include "frlog.h"
#include "frreport_comm.h"
#include "frct_comm.h"
#include "frreport_comm.h"

#include "jolt_core.h"
#include "jolt_comm.h"
#include "jolt_mar.h"

static char hex_asc[] = "0123456789abcdef";
#define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]

/*******************************************************************************
*  FUNC     :  释放内存
*  ARGS     :  pp_buffer
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void jolt_free(void **pp_buffer)
{
    if (pp_buffer == NULL || *pp_buffer == NULL)
        return;

    frfree(*pp_buffer);
    *pp_buffer = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  时间格式化成 2015-03-29 22:25:12.448671 的格式
*  ARGS     :  *p_tv                           (时间戳)
*           :  *p_time                         (buffer)
*           :  ui_time_size                    (buffer size)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC int __jolt_frtime2datetimestr(struct timeval *p_tv
                                        , char *p_time
                                        , unsigned int ui_time_size)
{
    struct tm *p_tm = NULL;

    if(p_tv == NULL || p_time == NULL || ui_time_size <= 1)
        return FR_FAIL;

    p_tm = localtime(&(p_tv->tv_sec));

    snprintf(p_time,ui_time_size,"%04d-%02d-%02d %02d:%02d:%02d.%06ld",
             p_tm->tm_year + 1900,p_tm->tm_mon + 1,p_tm->tm_mday,
             p_tm->tm_hour,p_tm->tm_min,p_tm->tm_sec,p_tv->tv_usec);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  打印时间
*  ARGS     :  st_timestamp                         (时间戳)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void jolt_print_timeval(struct timeval st_timestamp)
{
    char arr_buff[64];
    __jolt_frtime2datetimestr(&st_timestamp, arr_buff, sizeof(arr_buff));
    printf(":[%s]\n", arr_buff);
}

/*******************************************************************************
*  FUNC     :  格式化成十六进制字符串
*  ARGS     :  *p_inbuff    (输入的字符串)
*           :  i_len        (输入的字符串长度)
*           :  *p_outbuff   (格式化后的十六进制字符串)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void jolt_bin_to_hex_string(char *p_inbuff
                            , int i_len
                            , char *p_outbuff)
{
    int i_loop;
    char c;
    int i_used = 0;

    for (i_loop = 0; i_loop < i_len; i_loop++)
    {
        c = p_inbuff[i_loop];
        p_outbuff[i_used++] = hex_asc_hi(c);
        p_outbuff[i_used++] = hex_asc_lo(c);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  按一个字节打印十六进行字符串
*  ARGS     :  *p_buff  (char*字符串)
*           :  i_len   (字符串长度)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void jolt_print_hex_string(char *p_buff
                        , int i_len)
{
    int i_loop;

    for (i_loop = 0; i_loop < i_len; i_loop++)
        printf("%02x", p_buff[i_loop] & 0xFF);

    return;
}

/*******************************************************************************
*  FUNC     :  打印指定位置的包内容
*  ARGS     :  *p_st_jolt_packet                    (Jolt数据包)
*           :  i_pos                                (开始位置)
*           :  i_len                                (长度)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void jolt_print_packet_specified(L7_jolt_packet *p_st_jolt_packet
                                , int i_pos
                                , int i_len)
{
    if (p_st_jolt_packet == NULL)
        return;
    char *p_buff_tmp = NULL;
    if (bytebuff_show(p_st_jolt_packet->p_st_packet, i_pos, i_len, &p_buff_tmp) != FR_SUCC)
        return;
    jolt_print_hex_string(p_buff_tmp, i_len);
    jolt_free((void **) &p_buff_tmp);
    return;
}

/*******************************************************************************
*  FUNC     :  打印当前位置开始的包内容
*  ARGS     :  *p_st_jolt_packet                    (Jolt数据包)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void jolt_print_packet_current(L7_jolt_packet *p_st_jolt_packet)
{
    if (p_st_jolt_packet == NULL)
        return;
    char *p_buff_tmp = NULL;
    if (bytebuff_show(p_st_jolt_packet->p_st_packet, bytebuff_getPosition(p_st_jolt_packet->p_st_packet), bytebuff_remaining(p_st_jolt_packet->p_st_packet), &p_buff_tmp) != FR_SUCC)
        return;
    jolt_print_hex_string(p_buff_tmp, bytebuff_remaining(p_st_jolt_packet->p_st_packet));
    jolt_free((void **) &p_buff_tmp);
    return;
}

/*******************************************************************************
*  FUNC     :  打印整个包内容
*  ARGS     :  *p_st_jolt_packet                    (Jolt数据包)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void jolt_print_packet(L7_jolt_packet *p_st_jolt_packet)
{
    if (p_st_jolt_packet == NULL)
        return;
    char *p_buff_tmp = NULL;
    if (bytebuff_show(p_st_jolt_packet->p_st_packet, 0, bytebuff_length(p_st_jolt_packet->p_st_packet), &p_buff_tmp) != FR_SUCC)
        return;
    jolt_print_hex_string(p_buff_tmp, bytebuff_length(p_st_jolt_packet->p_st_packet));
    jolt_free((void **) &p_buff_tmp);
    return;
}

/*******************************************************************************
*  FUNC     :  判断是否处于分片包状态
*  ARGS     :  *p_st_jolt_packet                        (Jolt数据包)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int jolt_packet_is_in_fragment(L7_jolt_packet *p_st_jolt_packet)
{
    if (p_st_jolt_packet == NULL)
        return FR_NO;

    return (p_st_jolt_packet->fragment_state == APM_JOLT_FRAGMENT_NEED_NEXT_REQ_PACKET
            || p_st_jolt_packet->fragment_state == APM_JOLT_FRAGMENT_NEED_NEXT_RESP_PACKET) ? FR_YES : FR_NO;
}

/*******************************************************************************
*  FUNC     :  上报通信消息的请求信息
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int jolt_report_msg_data_req(Conntrack *p_st_conn
                            , L7session_jolt *p_st_sess
                            , char *p_title
                            , char *p_service_name
                            , char *p_service_method
                            , L7_jolt_packet *p_st_jolt_packet
                            , Frhash_header *p_st_hash_report)
{
    JOLT_PRINT_INFO("jolt_report_msg_data_req\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_jolt_private *p_st_session_private = (L7session_jolt_private *) frct_get_session_private(p_st_session);
    L7_jolt_stmt *p_st_jolt_stmt = p_st_session_private->p_st_jolt_stmt;
    Frlist_node *p_st_msg_data_node = NULL;
    L7_jolt_msg_data *p_st_jolt_msg_data = NULL;
    char *p_field_name = NULL;
    int i_field_name_len = 0;
    Frreport_body_data *p_st_body = NULL;
    Frreport_data *p_st_report_data = NULL;
    unsigned int ui_arg_count = 0;

    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;

    p_st_msg_data_node = FRLIST_FIRST_NODE(p_st_jolt_stmt->p_list_msg_data);
    while (p_st_msg_data_node)
    {
        p_st_jolt_msg_data = (L7_jolt_msg_data *) FRLIST_GET_NODE_DATA(p_st_msg_data_node);

        ui_arg_count++;
        i_field_name_len = strlen(APM_DTS_REPORT_REQ_ARG_DATA) + 4;
        if ((p_field_name = (char *) frmalloc(i_field_name_len * sizeof(char))) == NULL)
        {
            JOLT_MALLOCK_ERR;
            goto error;
        }
        snprintf(p_field_name, (size_t) i_field_name_len, "%s%d", APM_DTS_REPORT_REQ_ARG_DATA, p_st_jolt_msg_data->i_index);

        switch (p_st_jolt_msg_data->ui_type)
        {
            case APM_JOLT_SSHORT:
                if (frreport_body_l7_add_int(p_st_body, p_field_name, p_st_jolt_msg_data->s_short) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SINT:
                if (frreport_body_l7_add_int(p_st_body, p_field_name, p_st_jolt_msg_data->i_int) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SBYTE:
                if (frreport_body_l7_add_int(p_st_body, p_field_name, p_st_jolt_msg_data->c_char) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SFLOAT:
                if (frreport_body_l7_add_float(p_st_body, p_field_name, p_st_jolt_msg_data->f_float) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SDOUBLE:
                if (frreport_body_l7_add_double(p_st_body, p_field_name, p_st_jolt_msg_data->d_double) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SSTRING:
                if (frreport_body_l7_add_str(p_st_body, p_field_name, p_st_jolt_msg_data->p_string) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SBINARY:
                if (frreport_body_l7_add_bin(p_st_body, p_field_name, p_st_jolt_msg_data->p_string, p_st_jolt_msg_data->i_string_len) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SSTRUCT:
                if (frreport_body_l7_add_bin(p_st_body, p_field_name, p_st_jolt_msg_data->p_string, p_st_jolt_msg_data->i_string_len) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SMBSTRING:
                if (frreport_body_l7_add_str(p_st_body, p_field_name, p_st_jolt_msg_data->p_string) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SBOOLEAN:
                if (frreport_body_l7_add_int(p_st_body, p_field_name, p_st_jolt_msg_data->s_boolean) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SLONG:
                if (frreport_body_l7_add_long(p_st_body, p_field_name, (long) p_st_jolt_msg_data->ll_long) != FR_SUCC)
                    goto error;
                break;
            default:
                goto error;
        }

        jolt_free((void **) &p_field_name);
        p_st_msg_data_node = FRLIST_NEXT_NODE(p_st_msg_data_node);
    }

    if (frreport_body_l7_add_uint(p_st_body, APM_DTS_REPORT_REQ_ARG_SIZE, ui_arg_count) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_ID, p_st_session->arr_session_id) != FR_SUCC)
        goto error;
    if (p_st_sess->p_username != NULL)
    {
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_USERNAME, p_st_sess->p_username) != FR_SUCC)
            goto error;
    }
    if (p_st_sess->p_userrole != NULL)
    {
        if (frreport_body_l7_add_str(p_st_body, APM_DTS_REPORT_SESSION_USERROLE, p_st_sess->p_userrole) != FR_SUCC)
            goto error;
    }
    if (p_st_jolt_packet->ui_handler_id != 0)
    {
        if (frreport_body_l7_add_uint(p_st_body, APM_REPORT_KEY_TRANS_RELATED_ID, p_st_jolt_packet->ui_handler_id) != FR_SUCC)
            goto error;
    }
    if (p_title && frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, p_title) != FR_SUCC)
        goto error;
    if (p_service_name && frreport_body_l7_add_str(p_st_body, APM_DTS_REPORT_REQ_SERVICE_NAME, p_service_name) != FR_SUCC)
        goto error;
    if (p_service_method && frreport_body_l7_add_str(p_st_body, APM_DTS_REPORT_REQ_SERVICE_METHOD, p_service_method) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_connInfo(p_st_body, p_st_conn) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_ID, frct_seq_increase(p_st_conn)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_REQ_ISRESPREQUIRED, FR_YES) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_START_TIMESTAMP, &(p_st_jolt_packet->st_timestamp_first)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_END_TIMESTAMP, &(p_st_jolt_packet->st_timestamp_last)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_REQ_SEND_TIME_US, frtime_diff(&(p_st_jolt_packet->st_timestamp_first), &(p_st_jolt_packet->st_timestamp_last))) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_jolt_packet->ui_length) != FR_SUCC)
        goto error;

    frreport_body_l7list_free(&(p_st_session_private->p_report_comm));
    p_st_session_private->p_report_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_body);

    frreport_body_l7list_free(&(p_st_session_private->p_report_req));
    p_st_session_private->p_report_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_body);

    if ((p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ)) == NULL)
        goto error;

    if (frreport_data_add_body(p_st_report_data, p_st_body) != FR_SUCC)
        goto error;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) != FR_SUCC)
        goto error;

    p_st_jolt_stmt->st_req_end_timestamp.tv_sec = p_st_jolt_packet->st_timestamp_last.tv_sec;
    p_st_jolt_stmt->st_req_end_timestamp.tv_usec = p_st_jolt_packet->st_timestamp_last.tv_usec;

    return FR_SUCC;
error:
    jolt_free((void **) &p_field_name);
    frreport_body_free(&p_st_body);
    frreport_data_free(&p_st_report_data);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  上报通信消息的响应信息
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int jolt_report_msg_data_resp(Conntrack *p_st_conn
                            , int i_errno
                            , char *p_reason
                            , L7_jolt_packet *p_st_jolt_packet
                            , Frhash_header *p_st_hash_report)
{
    JOLT_PRINT_INFO("jolt_report_msg_data_resp\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_jolt_private *p_st_session_private = (L7session_jolt_private *) frct_get_session_private(p_st_session);
    L7_jolt_stmt *p_st_jolt_stmt = p_st_session_private->p_st_jolt_stmt;
    Frlist_node *p_st_msg_data_node = NULL;
    L7_jolt_msg_data *p_st_jolt_msg_data = NULL;
    char *p_field_name = NULL;
    int i_field_name_len = 0;
    Frreport_body_data *p_st_body = NULL;
    Frreport_data *p_st_report_data = NULL;
    unsigned int ui_return_count = 0;

    if (p_st_session_private->p_report_comm == NULL || p_st_session_private->p_report_req == NULL)
    {
        JOLT_PRINT_EMERG("Has no request data, do not report response\n");
        JOLT_FRLOG_ERROR("Has no request data, do not report response");
        return FR_SUCC;
    }

    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;

    p_st_msg_data_node = FRLIST_FIRST_NODE(p_st_jolt_stmt->p_list_msg_data);
    while (p_st_msg_data_node)
    {
        p_st_jolt_msg_data = (L7_jolt_msg_data *) FRLIST_GET_NODE_DATA(p_st_msg_data_node);

        ui_return_count++;
        i_field_name_len = strlen(APM_DTS_REPORT_RESP_ARG_DATA) + 4;
        if ((p_field_name = (char *) frmalloc(i_field_name_len * sizeof(char))) == NULL)
        {
            JOLT_MALLOCK_ERR;
            goto error;
        }
        snprintf(p_field_name, (size_t) i_field_name_len, "%s%d", APM_DTS_REPORT_RESP_ARG_DATA, p_st_jolt_msg_data->i_index);

        switch (p_st_jolt_msg_data->ui_type)
        {
            case APM_JOLT_SSHORT:
                if (frreport_body_l7_add_int(p_st_body, p_field_name, p_st_jolt_msg_data->s_short) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SINT:
                if (frreport_body_l7_add_int(p_st_body, p_field_name, p_st_jolt_msg_data->i_int) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SBYTE:
                if (frreport_body_l7_add_int(p_st_body, p_field_name, p_st_jolt_msg_data->c_char) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SFLOAT:
                if (frreport_body_l7_add_float(p_st_body, p_field_name, p_st_jolt_msg_data->f_float) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SDOUBLE:
                if (frreport_body_l7_add_double(p_st_body, p_field_name, p_st_jolt_msg_data->d_double) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SSTRING:
                if (frreport_body_l7_add_str(p_st_body, p_field_name, p_st_jolt_msg_data->p_string) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SBINARY:
                if (frreport_body_l7_add_bin(p_st_body, p_field_name, p_st_jolt_msg_data->p_string, p_st_jolt_msg_data->i_string_len) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SSTRUCT:
                if (frreport_body_l7_add_bin(p_st_body, p_field_name, p_st_jolt_msg_data->p_string, p_st_jolt_msg_data->i_string_len) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SMBSTRING:
                if (frreport_body_l7_add_str(p_st_body, p_field_name, p_st_jolt_msg_data->p_string) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SBOOLEAN:
                if (frreport_body_l7_add_int(p_st_body, p_field_name, p_st_jolt_msg_data->s_boolean) != FR_SUCC)
                    goto error;
                break;
            case APM_JOLT_SLONG:
                if (frreport_body_l7_add_long(p_st_body, p_field_name, (long) p_st_jolt_msg_data->ll_long) != FR_SUCC)
                    goto error;
                break;
            default:
                goto error;
        }

        jolt_free((void **) &p_field_name);
        p_st_msg_data_node = FRLIST_NEXT_NODE(p_st_msg_data_node);
    }

    if (frreport_body_l7_add_uint(p_st_body, APM_DTS_REPORT_RESP_ARG_SIZE, ui_return_count) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_RESP_CODE, i_errno) != FR_SUCC)
        goto error;
    if (p_reason != NULL)
    {
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_RESP_CODE_STRING, p_reason) != FR_SUCC)
            goto error;
    }

    if (FRREPORT_BODY_L7LIST_SET_COMM(p_st_body, &(p_st_session_private->p_report_comm)) != FR_SUCC)
        goto error;
    if (FRREPORT_BODY_L7LIST_SET_REQ(p_st_body, &(p_st_session_private->p_report_req)) != FR_SUCC)
        goto error;

    if (p_st_jolt_stmt->st_resp_start_timestamp.tv_sec != 0 || p_st_jolt_stmt->st_resp_start_timestamp.tv_usec != 0)
    {
        if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_RESP_START_TIMESTAMP, &(p_st_jolt_stmt->st_resp_start_timestamp)) != FR_SUCC)
            goto error;
    }
    else
    {
        if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_RESP_START_TIMESTAMP, &(p_st_jolt_packet->st_timestamp_first)) != FR_SUCC)
            goto error;
    }
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_RESP_END_TIMESTAMP, &(p_st_jolt_packet->st_timestamp_last)) != FR_SUCC)
        goto error;
    if (p_st_jolt_stmt->ul_resp_server_time_us != 0L)
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_SERVER_TIME_US, p_st_jolt_stmt->ul_resp_server_time_us) != FR_SUCC)
            goto error;
    }
    else if (p_st_jolt_stmt->st_resp_start_timestamp.tv_sec != 0 || p_st_jolt_stmt->st_resp_start_timestamp.tv_usec != 0)
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_SERVER_TIME_US, frtime_diff(&(p_st_jolt_stmt->st_req_end_timestamp), &(p_st_jolt_stmt->st_resp_start_timestamp))) != FR_SUCC)
            goto error;
    }
    else
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_SERVER_TIME_US, frtime_diff(&(p_st_jolt_stmt->st_req_end_timestamp), &(p_st_jolt_packet->st_timestamp_first))) != FR_SUCC)
            goto error;
    }
    if (p_st_jolt_stmt->st_resp_start_timestamp.tv_sec != 0 || p_st_jolt_stmt->st_resp_start_timestamp.tv_usec != 0)
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, frtime_diff(&(p_st_jolt_stmt->st_resp_start_timestamp), &(p_st_jolt_packet->st_timestamp_last))) != FR_SUCC)
            goto error;
    }
    else
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, frtime_diff(&(p_st_jolt_packet->st_timestamp_first), &(p_st_jolt_packet->st_timestamp_last))) != FR_SUCC)
            goto error;
    }
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_jolt_packet->ui_length) != FR_SUCC)
        goto error;

    if ((p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP)) == NULL)
        goto error;

    if (frreport_data_add_body(p_st_report_data, p_st_body) != FR_SUCC)
        goto error;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) != FR_SUCC)
        goto error;

    return FR_SUCC;
error:
    jolt_free((void **) &p_field_name);
    frreport_body_free(&p_st_body);
    frreport_data_free(&p_st_report_data);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  释放MsgData节点
*  ARGS     :  *p_st_node                               (节点)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void jolt_msg_data_node_free(Frlist_node *p_st_node)
{
    if (p_st_node == NULL)
    {
        JOLT_PRINT_EMERG("invalid parameter.\n");
        JOLT_FRLOG_ERROR("invalid parameter.");
        return;
    }

    L7_jolt_msg_data *p_st_jolt_msg_data = (L7_jolt_msg_data *) FRLIST_GET_NODE_DATA(p_st_node);
    jolt_free((void **) &(p_st_jolt_msg_data->p_string));
    jolt_free(&(p_st_node->data));

    return;
}

/*******************************************************************************
*  FUNC     :  释放 L7_jolt_stmt
*  ARGS     :  **pp_st_jolt_stmt                             (L7_jolt_stmt)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void jolt_free_stmt(L7_jolt_stmt **pp_st_jolt_stmt)
{
    if (pp_st_jolt_stmt == NULL || *pp_st_jolt_stmt == NULL)
        return;

    L7_jolt_stmt *p_st_jolt_stmt = *pp_st_jolt_stmt;
    frlist_destroy(p_st_jolt_stmt->p_list_msg_data, jolt_msg_data_node_free);
    jolt_free((void **) pp_st_jolt_stmt);

    return;
}

/*******************************************************************************
*  FUNC     :  初始化 L7_jolt_stmt
*  ARGS     :  *p_st_jolt_stmt                               (L7_jolt_stmt)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void jolt_init_stmt(L7_jolt_stmt *p_st_jolt_stmt)
{
    if (p_st_jolt_stmt == NULL)
        return;

    frlist_remove_all(p_st_jolt_stmt->p_list_msg_data, jolt_msg_data_node_free);
    memset(&p_st_jolt_stmt->st_req_end_timestamp, 0x0, sizeof(struct timeval));
    memset(&p_st_jolt_stmt->st_resp_start_timestamp, 0x0, sizeof(struct timeval));
    p_st_jolt_stmt->ul_resp_server_time_us = 0L;
    p_st_jolt_stmt->ui_msg_id = 0;

    return;
}
